#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <openssl/sha.h>  
#include <unistd.h>
#include "zlog.h"
#include "main.h"
#include "timet.h"
#include "file_save.h"
#include "math_statistics_func.h"
#include "json_func.h"


static int 		tm_hour;


uint8_t enable_spd_num(const spd_cfg_info spd[])
{
	uint8_t num = 0;
	
	for (uint8_t ch = 0; ch < SPD_CH_TOTAL; ch++)
	{
		if (spd[ch].spd_en == ON)
			num += 1;
	}
	return num;
}

uint8_t enable_chx_num(const chx_cfg_info chx[])
{
	uint8_t num = 0;
	
	for (uint8_t ch = 0; ch < ACC_CH_TOTAL; ch++)
	{
		if (chx[ch].chx_en == ON)
			num += 1;
	}
	return num;
}

void file_fill_file_head_format(file_info_head *head, const sys_cfg_info *sys, 
							const chx_cfg_info chx[], const spd_unit spd[], sys_runtime *rt)
{
	uint8_t chx_num;

	chx_num = enable_chx_num(chx);
	//即strcpy只用于字符串复制，并且它不仅复制字符串内容之外，还会复制字符串的结束符；
	memset((char*)head, DEFAULT_FILE_FILL_CHAR, sizeof(file_info_head));
	strlcpy(head->dev_name, sys->dev_name, sizeof(head->dev_name));
	strlcpy(head->dev_local, sys->dev_local, sizeof(head->dev_name));
	strlcpy(head->dev_sn, sys->dev_sn, sizeof(head->dev_sn));
	strlcpy(head->dev_type, sys->dev_type, sizeof(head->dev_type));
	//snprintf其后添加一个字符串结束符\0
	snprintf(head->spd_val[0], 8, "%.2f", spd[0].speed_val);
	snprintf(head->spd_val[1], 8, "%.2f", spd[1].speed_val);
	snprintf(head->chx_num, 4, "%03X", chx_num);
	snprintf(head->samp_freq, 8, "%d", sys->samp_freq);
	snprintf(head->amb_temp, 6, "%.2f", rt->sys_amb_temp);
	snprintf(head->disk_free, 10, "%.2f", sys->disk_free_size);
	strcpy(head->sys_status, "GOOD");

	get_time_str_fixed_format2(head->time);
}



void file_fill_chx_data_format(file_info_chx *head, uint8_t index, const chx_cfg_info chx[])
{
	memset((char*)head, DEFAULT_FILE_FILL_CHAR, sizeof(file_info_chx));
	
	if (index > ACC_CH_TOTAL)
		strcpy(head->chx_index, "UNDEF");
	else
		snprintf(head->chx_index, 6, "CH%d", index);

	strlcpy(head->chx_desc, chx[index].chx_desc, sizeof(head->chx_desc));

	switch(chx[index].chx_mode) {
		case SAFE :
			strcpy(head->chx_mode, "SAFE");
		break;
		case IEPE :
			strcpy(head->chx_mode, "IEPE");
		break;
		case DC :
			strcpy(head->chx_mode, "DC");
		break;
		case AC :
			strcpy(head->chx_mode, "AC");
		break;
		case TIB :
			strcpy(head->chx_mode, "TIB");
		break;
		case CAL :
			strcpy(head->chx_mode, "CAL");
		break;
		default :
			strcpy(head->chx_mode, "UNDEF");
		break;
	}
	snprintf(head->chx_sample_freq, 8, "%d", chx[index].chx_sample_freq);
	snprintf(head->chx_pga_gain, 8, "%.2f", chx[index].chx_pga_gain);
	snprintf(head->chx_drcc_gain, 8, "%.2f", chx[index].chx_drcc_gain);
	switch(chx[index].chx_fir_cutoff) 
	{
		case LPFNO :
			strcpy(head->chx_fir_cutoff , "LPFNONE");
			break;
		case LPF10K :
			strcpy(head->chx_fir_cutoff , "LPF10K");
			break;
		case LPF15K :
			strcpy(head->chx_fir_cutoff , "LPF15K");
			break;
		case LPF20K :
			strcpy(head->chx_fir_cutoff , "LPF20K");
			break;
		case LPF30K :
			strcpy(head->chx_fir_cutoff , "LPF30K");
			break;
		case LPF40K :
			strcpy(head->chx_fir_cutoff , "LPF40K");
			break;
		default :
			strcpy(head->chx_fir_cutoff , "LPFNONE");
			break;
	}
	snprintf(head->chx_sensor_sens, 8, "%.2f", chx[index].chx_sens);
	strcpy(head->chx_status_alarm , "GOOD");
	snprintf(head->chx_offset_val, 8, "%.2f", chx[index].chx_offset);

	switch(chx[index].chx_plug_det) {
		case INSERTED :
			strcpy(head->chx_plug_det , "INSERT");
		break;
		case REMOVED :
			strcpy(head->chx_plug_det , "REMOVE");
		break;
		default :
			strcpy(head->chx_plug_det , "REMOVE");
			break;
	}
	
	switch(chx[index].chx_pga_ef) {
		case EF_NORMAL :
			strcpy(head->chx_over_range , "NORMAL");
		break;
		case EF_ERROR :
			strcpy(head->chx_over_range , "ERROR");
		break;
		default :
			strcpy(head->chx_over_range , "NORMAL");
			break;
	}
	
	switch(chx[index].chx_pwr_a24v) {
		case A24V_NORMAL :
			strcpy(head->chx_over_range , "NORMAL");
		break;
		case A24V_ERROR :
			strcpy(head->chx_over_range , "ERROR");
		break;
		default :
			strcpy(head->chx_over_range , "NORMAL");
			break;
	}
	strlcpy(head->chx_sensor_type, chx[index].chx_sensor.type, sizeof(head->chx_sensor_type));
	strcpy(head->chx_date_type , "FLOAT");
	strcpy(head->chx_reserve , "RESERVE");
}




void file_fill_spd_data_format(file_info_spd *head, uint8_t index, const spd_cfg_info spd[])
{
	memset((char*)head, DEFAULT_FILE_FILL_CHAR, sizeof(file_info_spd));
	
	if (index > SPD_CH_TOTAL)
		strcpy(head->spd_index, "UNDEF");
	else
		snprintf(head->spd_index, 6, "SPD%d", index);

	strlcpy(head->spd_desc, spd[index].spd_desc, sizeof(head->spd_desc));

	switch(spd[index].spd_mode) {
		case MAGN :
			strcpy(head->spd_mode, "MAGN");
		break;
		case PHOTO :
			strcpy(head->spd_mode, "PHOTO");
		break;
		default :
			strcpy(head->spd_mode, "HANG");
		break;
	}

	//按照 format 格式化成字符串，并将字符串复制到 str 中，size 为要写入的字符的最大数目，
	//超过 size 会被截断。
	snprintf(head->spd_pulse, sizeof(head->spd_pulse), "%.1f", spd[index].spd_pulse);
}


static int save_file_name_get(char *file, char	*path)
{
	time_t t;
	char s1[50], s2[20];
	char folder[100] = "";

	time(&t);
	struct tm *curr_time = localtime(&t);
	//strftime 根据format中定义的格式化规则，格式化结构timeptr表示的时间，并把它存储在str中
	strftime(s1, sizeof(s1), "%04Y%02m%02d%H", curr_time);
	strftime(s2, sizeof(s2), "%04Y%02m%02d%H%M%S", curr_time);
	sprintf(folder, "%s%s%s", path, "/vdata/", s1);

	if(tm_hour != curr_time->tm_hour) {
		if(opendir(folder) == NULL) {								//文件夹不存在，建立文件夹
			if(mkdir(folder, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH) < 0) {
				dzlog_error("creat folder of save file %s failed!", folder);
				if (sys_cfg.debug == ON)
					printf("creat folder of save file %s failed!\n", folder);
				return FAILURE;
			}
		}
		tm_hour = curr_time->tm_hour;
	}

	sprintf(file, "%s/vib%s.dat", folder, s2);

	if (sys_cfg.debug == ON)
		printf("the new path of save file is %s creat succeed!\n", folder);

	return SUCCESS;
}


// 函数原型 size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
// ptr-- 这是指向要被写入的元素数组的指针。
// size-- 这是要被写入的每个元素的大小，以字节为单位。
// nmemb-- 这是元素的个数，每个元素的大小为 size 字节。
// stream-- 这是指向 FILE 对象的指针，该 FILE 对象指定了一个输出流



void vdata_file_save(sys_cfg_info *sys, sys_runtime *rt, chx_cfg_info chx[],
							acc_unit acc[], spd_cfg_info cspd[], spd_unit uspd[])
{
	uint16_t ch, chx_num;
	char file[FILE_PATH_LEN] = "";
	uint8_t sha256_digest[32];
	uint8_t sha256_temp[32 * ACC_CH_TOTAL];
	uint8_t sha256_ch = 0;
	uint32_t raw_g_len = 0;
	// uint32_t file_total_len = 0;
	FILE *fp;

	data_frame_len_info frame_len;
	file_info_head		fhead;
	file_info_chx		chead;
	// file_info_spd		shead;

	if ((save_file_name_get(file, sys->disk_path) == 0) && (sys->disk_data_save == ON)) {
		strcpy(rt->vdata_file_path, file);				//保存路径
		fp = fopen(file, "a+");
		if (fp == NULL) {
			dzlog_error("open save file %s failed!", file);
			dzlog_error("open file error, file have been created!");
			if (sys->debug == ON) {
				printf("open save file %s failed!n", file);
				perror("open file error, file have been created!\n");
			}		
		} else if (rt->disk_chk_flag == 0) {
			file_fill_file_head_format(&fhead, sys, chx, uspd, rt);
			raw_g_len = sys->duration * sys->samp_freq * sizeof(float);
			chx_num = enable_chx_num(chx);
			//file_total_len = 4 + 4 + sizeof(data_frame_len_info) + sizeof(file_info_head) 
			//	+ (sizeof(file_info_chx) + sizeof(td_calc_norl) + raw_g_len) * chx_num + 0 + 32 + 4;
			
			frame_len.file_info_len 	= sizeof(file_info_head);
			frame_len.file_info_code	= DATA_FRAME_FILE_INFO_CODE;
			frame_len.chx_head_len 		= sizeof(file_info_chx) * chx_num;
			frame_len.chx_head_code		= DATA_FRAME_CHX_HEAD_CODE;
			frame_len.eigen_data_len 	= sizeof(td_calc_norl) * chx_num;
			frame_len.eigen_data_code	= DATA_FRAME_EIGEN_DATA_CODE;
			frame_len.raw_data_len 		= raw_g_len * chx_num;
			frame_len.raw_data_code		= DATA_FRAME_RAW_DATA_CODE;
			frame_len.resv_data_len 	= 0;
			frame_len.resv_data_code	= DATA_FRAME_RESV_DATA_CODE;
			
			switch (sys->duration)
			{
				case 1 :
					fwrite(SAVE_FILE_HEAD_TYPEA1, sizeof(char), 4, fp);
					break;
				case 2 :
					fwrite(SAVE_FILE_HEAD_TYPEA2, sizeof(char), 4, fp);
					break;
				case 5 :
					fwrite(SAVE_FILE_HEAD_TYPEA5, sizeof(char), 4, fp);
					break;
				case 10 :
					fwrite(SAVE_FILE_HEAD_TYPEAA, sizeof(char), 4, fp);
					break;
				default :
					fwrite(SAVE_FILE_HEAD_TYPEA1, sizeof(char), 4, fp);
			}

			fwrite(COMM_PROTOCOL_VERSION, sizeof(char), 4, fp);							// 写入版本号
			fwrite((char *)&frame_len, sizeof(char), sizeof(data_frame_len_info), fp);	// 长度描述部分
			fwrite(&fhead, sizeof(char), sizeof(file_info_head), fp);					// 写入文件信息
			
			for(ch = 0; ch < ACC_CH_TOTAL; ch++) {
				if (chx[ch].chx_en == ON) {
					file_fill_chx_data_format(&chead, ch, chx);
					fwrite(&chead, sizeof(char), sizeof(file_info_chx), fp);			// 写入通道头信息
					//写入特征值
					fwrite(&(acc[ch].td_eigen_value), sizeof(char), sizeof(td_calc_norl), fp);
					//写入原始数据
					fwrite(acc[ch].td_vdata_raw_g, sizeof(char), raw_g_len, fp);
					SHA256((unsigned char *)acc[ch].td_vdata_raw_g, raw_g_len, &sha256_temp[32 * sha256_ch++]);
				}
			}
			
			/*
			for (ch = 0; ch < SPD_CH_TOTAL; ch++) {
				if (cspd[ch].spd_en == ON) {
					file_fill_spd_data_format(&shead, ch, cspd);
					fwrite(&shead, sizeof(char), sizeof(file_info_spd), fp);
				}
			}
			*/
			// sha256数据写入
			SHA256(sha256_temp, 32 * sha256_ch, sha256_digest);
			fwrite(sha256_digest, sizeof(char), sizeof(sha256_digest), fp);
			
			fwrite(SAVE_FILE_TAIL_CYHK, sizeof(char), 4, fp);
		}
		usleep(50000);					// 50ms
		system("sync");					// 必须同步，否则并没有真正写入卡中
		fclose(fp);
	}
}



